﻿using NPOI.SS.Formula.Functions;
using ST.Common.Util;
using ST.Common.Util.Security;
using ST.Common.Util.Text;
using ST.Common.Util.Xml;
using ST.WX.Common.Exceptions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml;

namespace ST.WX.Common.Pay
{
	/// <summary>
	/// 微信请求参数
	/// </summary>
	public class WXPayData : WXPayBase
	{
		public WXPayData() : base()
		{
		}

		public WXPayData(string appID, string mchID, string mchKey, WXPaySignType signType) : base(appID, mchID, mchKey, signType)
		{
		}

		/// <summary>
		/// 发送请求时将数据转换成xml格式内容（自动添加appid、mch_id、nonce_str、sign_type、sign参数）
		/// </summary>
		/// <returns></returns>
		protected virtual string ToXml(SortedDictionary<string, object> Values)
		{
			//数据为空时不能转化为xml格式
			if (Values == null || Values.Count == 0)
			{
				throw new WXPayException("支付请求参数不能为空");
			}
			switch (sign_type)
			{
				case WXPaySignType.HMACSHA256:
					Values["sign_type"] = SIGN_TYPE_HMACSHA256;
					break;
				case WXPaySignType.MD5:
					Values["sign_type"] = SIGN_TYPE_MD5;
					break;
				default:
					throw new WXPayException("签名算法不支持");
			}
			Values["appid"] = appid;
			Values["mch_id"] = mch_id;
			nonce_str = RandomGenerator.GetNonceStr();
			Values["nonce_str"] = nonce_str;
			sign = MakeSign(Values);
			Values["sign"] = sign;//所有参数赋值完成之后计算签名
			StringBuilder buf = new StringBuilder("<xml>");
			foreach (var item in Values)
			{
				//字段值不能为null，会影响后续流程
				if (item.Value == null)
				{
					continue;
					//throw new WXPayException("支付参数内部含有值为null的字段!");
				}

				if (item.Value.GetType() == typeof(int))
				{
					buf.Append("<" + item.Key + ">" + item.Value + "</" + item.Key + ">");
				}
				else if (item.Value.GetType() == typeof(string))
				{
					buf.Append("<" + item.Key + ">" + "<![CDATA[" + item.Value + "]]></" + item.Key + ">");
				}
				else//除了string和int类型不能含有其他数据类型
				{
					throw new WXPayException("支付参数字段数据类型错误!");
				}
			}
			buf.Append("</xml>");
			return buf.ToString();
		}

		/// <summary>
		/// 将具体接口对象转换成支付参数对象
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public virtual SortedDictionary<string, object> ConvertFromObj()
		{
			return null;
		}

		/// <summary>
		/// 发送请求时校验参数
		/// </summary>
		public virtual void Validate()
		{
			if (string.IsNullOrEmpty(appid))
			{
				throw new WXPayException("appid不能为空");
			}
			if (string.IsNullOrEmpty(mch_id))
			{
				throw new WXPayException("商户号不能为空");
			}
			if (string.IsNullOrEmpty(mch_key))
			{
				throw new WXPayException("支付密钥不能为空");
			}
		}

		/// <summary>
		/// 发送请求，并将返回内容解析成对象（未验证返回内容的正确性）
		/// </summary>
		/// <returns></returns>
		public virtual void SendRequest(WXPayRet ret, string url, string certFullPath, string certPasswd, int timeout = 5)
		{
			Validate();
			var valuesReq = ConvertFromObj();
			string xml = ToXml(valuesReq);
			string respText = HttpHelper.Post(url, xml, timeout, certFullPath, certPasswd, "text/xml");
			ret.mch_key = mch_key;
			ret.ParseAndValidate(respText);
		}

		/// <summary>
		/// 发送请求，并将返回内容解析成对象（未验证返回内容的正确性）
		/// </summary>
		/// <returns></returns>
		public virtual void SendRequest(WXPayRet ret, string url, int timeout = 5)
		{
			Validate();
			var valuesReq = ConvertFromObj();
			string xml = ToXml(valuesReq);
			string respText = HttpHelper.Post(url, xml, timeout, null, null, "text/xml");
			ret.mch_key = mch_key;
			ret.ParseAndValidate(respText);
		}
	}
}
